package IC.lir;

import java.util.LinkedList;
import java.util.HashMap;

import IC.AST.*;
import IC.lir.Instrunction.*;
import IC.lir.Instrunction.BinaryArithmeticInstruction.Operation;
import IC.lir.Instrunction.JumpInstruction.Condition;
import IC.SymbolTables.Types.BasicType;
import IC.SymbolTables.Types.ClassType;
import IC.SymbolTables.Types.Symbol;
import IC.SymbolTables.Types.BasicType.BasicTypeEnum;


/**
 * Constructor - Gets a LIR object containing initialized the class structure.
 * The Visit(Program) sets the literals list and the functions list, and returns the updated LIR object 
 * 
 * the GetLir() function returns the updated LIR object as well
 * 
 * The Visit() function returns the Parameter with the result or a memory class (depends on the inner state)
 * 
 */
public class FunctionBodyCreatorVisitor extends Visitor 
{
	private final Register _dummyRegister = new Register(-1);
	
	protected Lir _lirStruct;
	public Lir GetLir() { return _lirStruct; }
	
	protected Register _returnRegister;
	protected int _registerCounter;
	protected LinkedList<Instruction> _currentFunctionInstructions;
	
	 // The caller is responsible to all of those resume to the previous state
	protected LabelGenerator _labelGenerator;
	protected Label _lastEndLabel, _lastFalseLabel,
					_lastWhileEndLabel, _lastWhileStartLabel;
	
	protected ReturnAsWhat _returnAsWhat = ReturnAsWhat.Register;
	
	private HashMap<String, String> _paramMapping;
	
	private String _classID;
	
	public FunctionBodyCreatorVisitor(Lir lirStruct) 
	{
		_lirStruct = lirStruct; 
		Initialize();
	}
	
	public Object Visit(Program rootNode)
	{ 
		Initialize();
		return VisitSons(rootNode);
	}

	private void Initialize()
	{
		_currentFunctionInstructions = new LinkedList<Instruction>();
		_paramMapping = new HashMap<String, String>();
		_labelGenerator = new LabelGenerator();
		_returnAsWhat = ReturnAsWhat.Register;
		
		_lirStruct.ProgramEndLabel = _labelGenerator.GenerateLabel("labelEndProgram");
		
		_lirStruct.Functions.clear();
		_lirStruct.Literals.clear();
	}
	
	public Object Visit(ClassDeclaration node)
	{ 
		_classID = node.GetID();
		return VisitSons(node);
	}
	
	public Object Visit(Method node) 
	{
		InsertFormalsIntoMapping(node);
		
		_currentFunctionInstructions = new LinkedList<Instruction>();
		node.GetScope().Visit(this);
		
		//any function must have a return instruction! (for void functions)
			//except main that must have an exit() function
		String funcLIRName = LirFunction.GenerateLIRFuncName(_classID, node.GetID(), node);
		_currentFunctionInstructions.add(
				funcLIRName.equals(LirFunction.MainLabelString) ?
						new JumpInstruction(Condition.None, _lirStruct.ProgramEndLabel)
				:
						new ReturnInstruction(new Immediate(797979)));
		_lirStruct.Functions.add(
				new LirFunction(
						new LabelDecl(LirFunction.GenerateLIRFuncName(_classID, node.GetID(), node)),
						_currentFunctionInstructions,
						node));
		return null;
	}
	
	private void InsertFormalsIntoMapping(Method node)
	{
		_paramMapping.clear();
		int count = 0;
		for (Formal formal : node.GetFormals())
			_paramMapping.put(formal.GetID(), ParamDataBind.Prefix + count++);
	}
	
	public Object Visit(ScopeStatement node)
	{ 
		return VisitSons(node);
	}
	
	public Object Visit(DeclorationStatement node)
	{
		_registerCounter = 0;
		if (node.GetExpression() != null)
			_currentFunctionInstructions.add(
					new VaribleMemory(UniqueVaribleName(node.GetID(), node)).Store(
							(Storable)InsureNotNegativeImmediate(
									(Storable)(node.GetExpression().Visit(this)))));
		return null; 
	}
	
	public Object Visit(ContinueStatement node)
	{
		_currentFunctionInstructions.add(new JumpInstruction(Condition.None, _lastWhileStartLabel));
		return null;
	}
	
	public Object Visit(BreakStatement node) 
	{
		_currentFunctionInstructions.add(new JumpInstruction(Condition.None, _lastWhileEndLabel));
		return null;
	}

	public Object Visit(AssignStatement node)
	{
		_registerCounter = 0;
		
		_returnAsWhat = ReturnAsWhat.Memory;
		Memory where = (Memory)(node.GetWhereTo().Visit(this));
		_returnAsWhat = ReturnAsWhat.Register;
		
		_currentFunctionInstructions.add(where.Store(
				(Storable)InsureNotNegativeImmediate(
						((Data)node.GetWhat().Visit(this)))));
				
		return null; 
	}
	
	public Object Visit(ReturnStatement node)
	{
		_registerCounter = 0;
		
		_returnAsWhat = ReturnAsWhat.SimpleMemory;
		Data retValue = InsureNotNegativeImmediate(
				(node.GetReturnValue() == null) ?
						new Immediate(0)
					:
						(Data)(node.GetReturnValue().Visit(this)));
		
		_returnAsWhat = ReturnAsWhat.Register;
					
		_currentFunctionInstructions.add(
				new ReturnInstruction(retValue));
		
		return null;
	}
	
	public Object Visit(WhileStatement node)
	{
		Label lastStartLabel = _lastWhileStartLabel, 
		lastEndLabel = _lastWhileEndLabel;
		
		_lastWhileStartLabel = _labelGenerator.GenerateLabel("WhileStartLabel");
		_lastWhileEndLabel =_labelGenerator.GenerateLabel("WhileEndLabel");
		
		WhileStatementImpl(node);
		
		_lastWhileStartLabel = lastStartLabel;
		_lastWhileEndLabel = lastEndLabel;
		return null;
	}
	
	private void WhileStatementImpl(WhileStatement node)
	{
		_registerCounter = 0;
		
		//that means the expression was evaluated in compile time
		if (node.GetExpression().IsExpValueSet())
		{
			//the Expression is false.
			if (node.GetExpression().GetExpValue() == 0)
				return;

			_currentFunctionInstructions.add(new LabelDecl(_lastWhileStartLabel));
			node.GetSatement().Visit(this);
			
			_currentFunctionInstructions.add(
					new JumpInstruction(Condition.None, _lastWhileStartLabel));
			_currentFunctionInstructions.add(new LabelDecl(_lastWhileEndLabel));
		}
		

		LinkedList<Instruction> whileExpressionInstructions,
				tempInstructionsList = _currentFunctionInstructions;
		_currentFunctionInstructions = new LinkedList<Instruction>();
		
		Data whileExpression = (Data)(node.GetExpression().Visit(this));
		
		_currentFunctionInstructions.add(
				new CompareInstuction(
						new Immediate(0),
						MakeSureDataIsRegister(whileExpression)));
		_currentFunctionInstructions.add(
				new JumpInstruction(Condition.True, _lastWhileEndLabel));
		
		whileExpressionInstructions = _currentFunctionInstructions;
		_currentFunctionInstructions = tempInstructionsList;
		_currentFunctionInstructions.addAll(whileExpressionInstructions);
		
		_currentFunctionInstructions.add(new LabelDecl(_lastWhileStartLabel));
		node.GetSatement().Visit(this);
		
		//testing the condition at the end to prevent a jump to start and back to the end (in case of failure)
		_currentFunctionInstructions.addAll(whileExpressionInstructions);
		
		_currentFunctionInstructions.add(
				new JumpInstruction(Condition.None, _lastWhileStartLabel));
		_currentFunctionInstructions.add(new LabelDecl(_lastWhileEndLabel));
	}
	
	public Object Visit(IfStatement node)
	{		
		Label lastEndLabel = _lastEndLabel, 
			lastFalseLabel = _lastFalseLabel;
		
		_lastEndLabel = _labelGenerator.GenerateLabel("EndLabel");
		if(node.GetSecondPart() != null)
			_lastFalseLabel = _labelGenerator.GenerateLabel("FalseLabel");
		
		IfStatementImpl(node);
		
		_lastEndLabel = lastEndLabel;
		_lastFalseLabel = lastFalseLabel;
		return null;
	}
	
	private void IfStatementImpl(IfStatement node)
	{
		_registerCounter = 0;
		
		boolean isExpressionImmediate, ifExpressionValue = false;
		if (isExpressionImmediate = node.GetIfExpression().IsExpValueSet())
			ifExpressionValue = node.GetIfExpression().GetExpValue() == 1;
		
		if (!isExpressionImmediate)
			_currentFunctionInstructions.add(
					new CompareInstuction(
							new Immediate(0),
							MakeSureDataIsRegister((Data)node.GetIfExpression().Visit(this))));
		//the MakeSureDataIsRegister can allocate a register that is not needed any more
		_registerCounter = 0;
		
		if (!isExpressionImmediate)
		{
			_currentFunctionInstructions.add(
					new JumpInstruction(
							Condition.True, 
							node.GetSecondPart() == null ?
									_lastEndLabel
								:
									_lastFalseLabel));
		}
		
		if (!isExpressionImmediate || ifExpressionValue)
			node.GetFirstPart().Visit(this);
		
		if ((!isExpressionImmediate) && (node.GetSecondPart() != null))
		{
			_currentFunctionInstructions.add(
					new JumpInstruction(
							Condition.None, _lastEndLabel));
			_currentFunctionInstructions.add(new LabelDecl(_lastFalseLabel));
		}
		
		if ((!isExpressionImmediate || !ifExpressionValue) && (node.GetSecondPart() != null))
			node.GetSecondPart().Visit(this);
		
		if (!isExpressionImmediate)
			_currentFunctionInstructions.add(new LabelDecl(_lastEndLabel));
	}
	
	public Object Visit(SimpleLocation node)
	{
		//Find it whether it's static or not.
		Symbol tempSym;
		if ((tempSym = node.GetSymbolTable().GetSymbol(node.GetID(), false)) == null)
			tempSym = node.GetSymbolTable().GetSymbol(node.GetID(), true);
		
		VaribleMemory mem = null;
		if (tempSym.GetKind().equals(Symbol.Kind.VARIABLE))
			mem = new VaribleMemory(UniqueVaribleName(node.GetID(), node));
		else if (tempSym.GetKind().equals(Symbol.Kind.FORMAL))
			mem = new VaribleMemory(_paramMapping.get(node.GetID()));
		else if (tempSym.GetKind().equals(Symbol.Kind.FIELD))
		{
			ThisExpression thisExpression = new ThisExpression(node.GetInterval());
			thisExpression.SetType(new ClassType(_classID, null));
			return new DotLocation(
					node.GetInterval(), 
					thisExpression, 
					node.GetID())
				.Visit(this);
		}
		
		return ReturnAsMemoryOrRegister(mem);
	}
	
	public Object Visit(ThisExpression node)
	{
		return ReturnAsMemoryOrRegister(new VaribleMemory("this"));
	}
	
	public Object Visit(LengthExpression node)
	{
		int registerCounter = _registerCounter;
		ReturnAsWhat lastReturnState = _returnAsWhat;
		
		_returnAsWhat = ReturnAsWhat.SimpleMemory;
		Data obj = (Data)node.GetExpression().Visit(this);
		_returnAsWhat = lastReturnState;
		
		_registerCounter = registerCounter;
		Register retRegister;
		if (obj instanceof VaribleMemory)
			_currentFunctionInstructions.add(new ArrayLength(
				(VaribleMemory)obj, retRegister = new Register(_registerCounter++)));
		else
			_currentFunctionInstructions.add(new ArrayLength(
					(Register)obj, retRegister = (Register)obj));
		return retRegister;
	}
	
	public Object Visit(UnaryOperationExpression node)
	{
		if (node.GetOperation().equals(UnaryOperationExpression.Operation.Minus))
			return GenerateUnaryMinusCode(node);
		else if (node.GetOperation().equals(UnaryOperationExpression.Operation.Not))
			return GenerateNotCode(node);
		return null;
	}
	
	protected Data InsureNotNegativeImmediate(Data data)
	{
		if (!(data instanceof Immediate))
			return data;
		if (((Immediate)data).GetValue() >= 0)
			return data;
		
		Register retRegister = MakeSureDataIsRegister(new Immediate(-((Immediate)data).GetValue()));
		_currentFunctionInstructions.add(new NegativeInstruction(retRegister));
		
		return retRegister;
	}
	
	protected Storable GenerateUnaryMinusCode(UnaryOperationExpression node)
	{
		Register retRegister = MakeSureDataIsRegister((Data)(node.GetExpression().Visit(this)));
		_currentFunctionInstructions.add(new NegativeInstruction(retRegister));
		
		return retRegister;
	}
	
	protected Storable GenerateNotCode(UnaryOperationExpression node)
	{
		Register retRegister = MakeSureDataIsRegister((Data)(node.GetExpression().Visit(this)));
		_currentFunctionInstructions.add(new BinaryArithmeticInstruction(Operation.Xor, new Immediate(1), retRegister));
		
		return retRegister;
	}
	
	public Object Visit(BinaryOperationExpression node)
	{
		if (node.GetType().equals(new IC.SymbolTables.Types.BasicType(BasicTypeEnum.INT)))
			return GenerateArithmeticBinaryCode(node.GetOperation(), node.GetFirstExp(), node.GetSecondExp(), node);
		if (node.GetType().equals(new IC.SymbolTables.Types.BasicType(BasicTypeEnum.STRING)))
			return GenerateStringCatCode(node.GetFirstExp(), node.GetSecondExp(), node);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.And))
			return GenerateAndOrCode(node, false);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.Or))
			return GenerateAndOrCode(node, true);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.Equal))
			return GenerateCompareCode(node, Condition.True);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.NotEqual))
			return GenerateCompareCode(node, Condition.False);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.More))
			return GenerateCompareCode(node, Condition.Greater);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.MoreOrEqual))
			return GenerateCompareCode(node, Condition.GreaterOrEqule);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.Less))
			return GenerateCompareCode(node, Condition.Less);
		else if (node.GetOperation().equals(BinaryOperationExpression.Operation.LessOrEqual))
			return GenerateCompareCode(node, Condition.LessOrEqule);
		return null;
	}
	
	//can't be optimized since the first expression MUST be evaluated first, always first
	private Storable GenerateAndOrCode(BinaryOperationExpression node, boolean isOr)
	{
		if (node.IsExpValueSet())
			return new Immediate(node.GetExpValue());

		int registerCounter = _registerCounter;

		boolean firstImmediateFlag = node.GetFirstExp().IsExpValueSet(),
				secondImmediateFlag = node.GetSecondExp().IsExpValueSet();		
		
		if (firstImmediateFlag)
		{
			boolean value = node.GetFirstExp().GetExpValue() == 1;
			if (isOr && value)
				return new Immediate(true);
			if (!isOr && !value)
				return new Immediate(false);
			else	
				return MakeSureDataIsRegister((Data)(node.GetSecondExp().Visit(this)));
		}
		
		if (secondImmediateFlag)
		{
			//first Expression must be evaluated
			Register retRegister = MakeSureDataIsRegister((Data)(node.GetFirstExp().Visit(this)));
			_registerCounter = registerCounter;
			
			boolean value = node.GetSecondExp().GetExpValue() == 1;
			if (isOr && value)
				return new Immediate(true);
			if (!isOr && !value)
				return new Immediate(false);
			
			_registerCounter = retRegister.GetIndex() + 1;
			return retRegister;
		}
		
		Label lastEndLabel = _lastEndLabel;
		_lastEndLabel = _labelGenerator.GenerateLabel("EndLabel");
		
		Register retRegister = MakeSureDataIsRegister((Data)(node.GetFirstExp().Visit(this)));
		
		_currentFunctionInstructions.add(new CompareInstuction(new Immediate(isOr ? true : false), retRegister));
		_currentFunctionInstructions.add(new JumpInstruction(Condition.True, _lastEndLabel));
		
		_registerCounter = registerCounter;
		retRegister = MakeSureDataIsRegister((Data)(node.GetSecondExp().Visit(this)));
		_currentFunctionInstructions.add(new LabelDecl(_lastEndLabel));

		_lastEndLabel = lastEndLabel;
		return retRegister;
	}
	
	protected Storable GenerateCompareCode(BinaryOperationExpression node, Condition jumpTrueCond)
	{
		
		Label lastEndLabel = _lastEndLabel,
			lastFalseLabel = _lastFalseLabel;
		_lastEndLabel = _labelGenerator.GenerateLabel("EndLabel");
		_lastFalseLabel = _labelGenerator.GenerateLabel("FalseLabel");
		
		int registerCounter = _registerCounter;
		
		Storable ret = GenerateCompareCodeImplementaion(node, jumpTrueCond);
		_registerCounter = registerCounter + (ret instanceof Register ? 1 : 0);
		
		_lastEndLabel = lastEndLabel;
		_lastFalseLabel = lastFalseLabel;
		return ret;
	}
	
	protected Storable GenerateCompareCodeImplementaion(BinaryOperationExpression node, Condition jumpTrueCond)
	{
		if (node.IsExpValueSet())
			return new Immediate(node.GetExpValue());
		
		int lastRegisterCount = _registerCounter;
		Register retRegister = MakeSureDataIsRegister(
				InsureNotNegativeImmediate(
						(Data)(node.GetFirstExp().Visit(this))));
		_registerCounter = lastRegisterCount + 1;
		
		ReturnAsWhat returnAsWhat = _returnAsWhat;
		
		_returnAsWhat = ReturnAsWhat.SimpleMemory;
		Data secondOperand = InsureNotNegativeImmediate((Data)(node.GetSecondExp().Visit(this)));
		_returnAsWhat = returnAsWhat;
		
		InsertCompareCodeLogic(retRegister, secondOperand, jumpTrueCond);
		
		_registerCounter = lastRegisterCount + 1;
		return retRegister;
	}
	
	protected void InsertCompareCodeLogic(Register retRegister, Data secondOperand, Condition jumpTrueCond)
	{
		_currentFunctionInstructions.add(new CompareInstuction(secondOperand, retRegister));
		_currentFunctionInstructions.add(new JumpInstruction(jumpTrueCond, _lastFalseLabel));
		
		_currentFunctionInstructions.add(new MoveInstruction(retRegister, new Immediate(0)));
		_currentFunctionInstructions.add(new JumpInstruction(Condition.None, _lastEndLabel));
		_currentFunctionInstructions.add(new LabelDecl(_lastFalseLabel));
		_currentFunctionInstructions.add(new MoveInstruction(retRegister, new Immediate(1)));
		_currentFunctionInstructions.add(new LabelDecl(_lastEndLabel));
	}
	
	protected Data GenerateStringCatCode(Expression first, Expression second, ASTNode node)
	{
		if (node.IsExpValueSet())
			return (Data)(new QuoteLiteral(node.GetInterval(), node.GetExpStringValue()).Visit(this));
		
		ReturnAsWhat returnAsWhat = _returnAsWhat;

		_returnAsWhat = ReturnAsWhat.Register;
		Register retRegister = (Register)(first.Visit(this));
		
		_returnAsWhat = ReturnAsWhat.SimpleMemory;
		Data secondParam = (Data)(second.Visit(this));
		
		_returnAsWhat = returnAsWhat;
		
		_currentFunctionInstructions.add(
				new StringCatInstruction(retRegister, retRegister, secondParam));
		_registerCounter = retRegister.GetIndex() + 1;
		return retRegister;
	}
	
	
	protected Storable GenerateArithmeticBinaryCode(BinaryOperationExpression.Operation op, Expression first, Expression second, ASTNode node)
	{
		if (node.IsExpValueSet())
			return new Immediate(node.GetExpValue());
		
		Register retRegister = MakeSureDataIsRegister(InsureNotNegativeImmediate((Data)first.Visit(this)));
		_registerCounter = retRegister.GetIndex() + 1;

		ReturnAsWhat returnAsWhat = _returnAsWhat;
		
		_returnAsWhat = ReturnAsWhat.SimpleMemory;
		 Data secondOperand = InsureNotNegativeImmediate((Data)(second.Visit(this)));
		 _registerCounter = retRegister.GetIndex() + 1;
		_returnAsWhat = returnAsWhat;
		
		_currentFunctionInstructions.add(
				new BinaryArithmeticInstruction(
						ConvertOperationType(op), 
						secondOperand, 
						retRegister));
		return retRegister;
	}
	
	protected BinaryArithmeticInstruction.Operation ConvertOperationType(BinaryOperationExpression.Operation op)
	{
		if (op.equals(BinaryOperationExpression.Operation.Add))
			return Operation.Add;
		if (op.equals(BinaryOperationExpression.Operation.Sub))
			return Operation.Sub;
		if (op.equals(BinaryOperationExpression.Operation.Div))
			return Operation.Div;
		if (op.equals(BinaryOperationExpression.Operation.Mult))
			return Operation.Mul;
		if (op.equals(BinaryOperationExpression.Operation.Mod))
			return Operation.Mod;
		return null;
	}
	
	public Object Visit(NewClassExpression node)
	{
		Register retRegister = new Register(_registerCounter++);
		
		_currentFunctionInstructions.add(
				new MemoryAlocationInstruction(retRegister, _lirStruct.ClassStructures.get(node.GetClassID())));
		_currentFunctionInstructions.add(
				new FieldStoreInstruction(
						new FieldMemory(retRegister, 0), 
						new DispechVector(node.GetClassID())));
		
		return retRegister;
	}
	
	public Object Visit(NewArrayExpression node)
	{
		Register retRegister = new Register(_registerCounter);
		
		Data size;
		if (node.GetSizeExpression().IsExpValueSet())
			size = new Immediate(4 * node.GetSizeExpression().GetExpValue());
		else
		{
			Expression tempExp = new LiteralExpression(new IntegerLiteral(node.GetInterval(), 4));
			tempExp.SetType(new BasicType(BasicTypeEnum.INT));
			tempExp = new BinaryOperationExpression(BinaryOperationExpression.Operation.Mult, 
					node.GetSizeExpression(),
					tempExp);
			tempExp.SetType(new BasicType(BasicTypeEnum.INT));
			
			ReturnAsWhat returnAsWhat = _returnAsWhat;
			
			_returnAsWhat = ReturnAsWhat.SimpleMemory;
			size =  InsureNotNegativeImmediate((Data)tempExp.Visit(this));
			_returnAsWhat = returnAsWhat;
		}
		
		_currentFunctionInstructions.add(
				new ArrayAlocationInstruction(
						retRegister,
						size));
		_registerCounter = retRegister.GetIndex() + 1;
		return retRegister;
	}
	

	public Object Visit(FunctionCallStatement node)
	{
		_returnRegister = _dummyRegister;
		_registerCounter = 0;
		node.GetFunctionCall().Visit(this);
		return null; 
	}
	
	//the function is 100% not of void return type because :
	//		an expression must return it value somewhere
	public Object Visit(FunctionCallExpression node)
	{
		Register lastRetRegister = _returnRegister;
		
		//automatically using the return register as one of the params
		Register retRegister = _returnRegister = new Register(_registerCounter);
		node.GetFunctionCall().Visit(this);
		_registerCounter = retRegister.GetIndex() + 1;
		
		_returnRegister = lastRetRegister;
		return retRegister;
	}
	
	public Object Visit(VirtualFunctionCall node)
	{
		_currentFunctionInstructions.add(
				new VirtualFunctionCallInstruction(
						_returnRegister, 
						MakeSureDataIsRegister((Data)(node.GetInvokedExpression().Visit(this))), 
						_lirStruct.ClassStructures.get((node.GetInvokedExpression()).GetType().toString()).
								GetMethodIndex(node.GetFunctionName()),
						ConvertExpressionListToParams(node.GetParams()),
						node));
		return null;
	}
	
	public Object Visit(StaticFunctionCall node)
	{
		_currentFunctionInstructions.add(
				node.GetClassName().equals("Library") ?
						new LibraryFunctionCallInstruction(
								_returnRegister,
								node.GetFunctionName(),
								ConvertExpressionListToParams(node.GetParams()),
								node)
					:
						new StaticFunctionCallInstruction(
								_returnRegister, 
								node.GetClassName(),
								node.GetFunctionName(),
								ConvertExpressionListToParams(node.GetParams()),
								node));
		return null;
	}
	
	protected LinkedList<Data> ConvertExpressionListToParams(LinkedList<Expression> list)
	{
		ReturnAsWhat returnAsWhat = _returnAsWhat;
		_returnAsWhat = ReturnAsWhat.SimpleMemory;

		LinkedList<Data> ret = new LinkedList<Data>();
		for (Expression exp : list)
			ret.add((Data)exp.Visit(this));

		_returnAsWhat = returnAsWhat;
		return ret;
	}
	
	public Object Visit(LiteralExpression node) { return node.GetLiteral().Visit(this); }
	
	public Object Visit(BooleanLiteral node) { return new Immediate(node.GetVaule() ? 1 : 0); }
	public Object Visit(IntegerLiteral node) { return new Immediate(node.GetVaule()); }
	public Object Visit(NullLiteral node) { return new Immediate(0); }
	
	public Object Visit(QuoteLiteral node)
	{
		return ReturnAsMemoryOrRegister(
				new VaribleMemory(_lirStruct.Literals.GetLabel(node.GetValue())));
	}
	
	public Object Visit(ArrayLocation node)
	{
		ReturnAsWhat returnAsWhat = _returnAsWhat;
		
		_returnAsWhat = ReturnAsWhat.Register;
		Register returnRegister = (Register)node.GetArray().Visit(this);
		_registerCounter = returnRegister.GetIndex() + 1;
		
		_returnAsWhat = ReturnAsWhat.SimpleMemory;
		Data index = (Data)node.GetIndex().Visit(this);
		_returnAsWhat = returnAsWhat;
		
		return ReturnAsMemoryOrRegister(
				index instanceof VaribleMemory ? 
						new ArrayMemory(returnRegister, (VaribleMemory)index)
					:
						new ArrayMemory(returnRegister, (Storable)index));
	}
	
	public Object Visit(DotLocation node)
	{
		ReturnAsWhat returnAsWhat = _returnAsWhat;
		
		_returnAsWhat = ReturnAsWhat.Register;
		Register retRegister = (Register)node.GetLeftExpression().Visit(this);
		_returnAsWhat = returnAsWhat;
		
		return ReturnAsMemoryOrRegister(new FieldMemory(
				retRegister, 
				_lirStruct.ClassStructures.
						get(node.GetLeftExpression().GetType().toString()).
								GetFieldIndex(node.GetRightID())));
	}
	
	protected Register MakeSureDataIsRegister(Data data)
	{
		Register retRegister;
		if (data instanceof Register)
			return (Register)data;
		else if (data instanceof Memory)
		{
			_currentFunctionInstructions.add(
				((Memory)data).Load(_registerCounter));
			retRegister = ((Memory)data).GetStoreRegister(_registerCounter);
			_registerCounter = retRegister.GetIndex() + 1;
		}
		else
			_currentFunctionInstructions.add(
					new MoveInstruction(
							retRegister = new Register(_registerCounter++), 
							data));	
		return retRegister;
	}
	
	private String UniqueVaribleName(String str, ASTNode node)
	{
		return String.format("uniqueName__%s__%s", 
				node.GetSymbolTable().GetUniqueName().
					replace(' ', '_').
					replace("(", "LP").
					replace(")", "RP"), 
				str);
	}
	
	/**
	 * @param mem the data that has to be returned as Memory or to be moved into Register depends on  _returnAsWhat state
	 * 
	 * @return the Data as memory or Register depends on the _returnAsWhat state.
	 * 			In case that the return is in a Register allocates a new Register.
	 */
	protected Data ReturnAsMemoryOrRegister(Memory mem)
	{
		if (_returnAsWhat.equals(ReturnAsWhat.Memory)
				|| (_returnAsWhat.equals(ReturnAsWhat.SimpleMemory)
						&& mem instanceof VaribleMemory))
			return mem;
		return MakeSureDataIsRegister(mem);
	}
	
	protected enum ReturnAsWhat
	{
		Register(0),
		Memory(1),
		SimpleMemory(2);
		
		private int _index;
		private ReturnAsWhat(int index) { _index = index; }
		
		public boolean equals(ReturnAsWhat compare) { return _index == compare._index; }
	}
}
